using System;
using System.Collections.Generic;
using System.Data;
using FluentNHibernate.Cfg;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace NHibernateInsight.Tests.Infrastructure.Data
{
    public abstract class DatabaseUsageStrategyBase : IDatabaseUsageStrategy
    {
        private readonly string _databaseName;
        private ISessionFactory _sessionFactory;
        private ISession _sesssion;
        private Configuration _configuration;

        protected DatabaseUsageStrategyBase(string databaseName)
        {
            _databaseName = databaseName;
        }

        public ISession CurrentSession
        {
            get
            {
                return _sesssion ?? (_sesssion = CurrentSessionFactory.OpenSession());
            }
        }
        public ISessionFactory CurrentSessionFactory
        {
            get { return _sessionFactory; }
        }
        public Configuration CurrentConfiguration
        {
            get { return _configuration; }
        }

        public IDbConnection ExistingConnection
        {
            get
            {
                return CurrentSession.Connection;
            }
        }

        protected string DatabaseName
        {
            get
            {
                return _databaseName;
            }
        }

        public abstract void PrepareDatabaseMedia();
        public abstract void DropDatabaseMedia();
        public abstract IDictionary<string, string> ConfigurationProperties { get; }



        public virtual void Init(Action<MappingConfiguration> with_mappings)
        {
            var configuration = new Configuration();
                configuration.AddProperties(ConfigurationProperties);
            
            var fluentConfiguration = Fluently.Configure(configuration);
                fluentConfiguration.Mappings(with_mappings);

            _sessionFactory = fluentConfiguration.BuildSessionFactory();
            _configuration = fluentConfiguration.BuildConfiguration();
                   }

        public virtual void CleanupResources()
        {
            var openConnection = ExistingConnection;

            _DisposeOfSessionAndSessionFactory();


            //explicit disposing of connection is required for in memory databases
            if (openConnection != null) openConnection.Dispose();
        }

        public bool HasDatabaseBeenCreated
        {
            get; set;
        }

        public bool HideCreateAndDropDbSql
        {
            get; set;
        }
        public bool HideCreateAndDropSchemaSql
        {
            get;
            set;
        }

        public virtual void ReCreateDatabaseSchema()
        {
            if (HasDatabaseBeenCreated == false) return;

            new SchemaExport(CurrentConfiguration).Execute((HideCreateAndDropSchemaSql == false), true, false, ExistingConnection, null);
        }
        public virtual void DropSchema()
        {
            if (HasDatabaseBeenCreated == false) return;

            new SchemaExport(CurrentConfiguration).Execute((HideCreateAndDropSchemaSql == false), false, true, ExistingConnection, null);
        }


        private void _DisposeOfSessionAndSessionFactory()
        {
            if (CurrentSession.IsOpen)
                CurrentSession.Close();

            CurrentSession.Dispose();

            CurrentSessionFactory.Dispose();
        }
    }
}